#pragma once

#include "list.h"

template<bool condition, typename first, typename second>
struct if_tool
{
};

template<typename first, typename second>
struct if_tool<true, first, second>
{
   typedef first result_;
};

template<typename first, typename second>
struct if_tool<false, first, second>
{
   typedef second result_;
};

template<typename list>
struct normalize
{
   typedef typename if_tool<
      ((list::head_) == 0),
      typename normalize<
         typename list::tail_
      >::result_,
      list
   >::result_ result_;
};

template<>
struct normalize<empty_list_t>
{
   typedef empty_list_t result_;
};

template<bool condition, size_t first, size_t second>
struct compare_int_tool
{
};

template<size_t first, size_t second>
struct compare_int_tool<true, first, second>
{
   static const size_t result_ = first;
};

template<size_t first, size_t second>
struct compare_int_tool<false, first, second>
{
   static const size_t result_ = second;
};

template<typename first, typename second>
struct compare_to_int
{
   static const int result_ = compare_int_tool<
      (first::head_ != second::head_),
      first::head_ - second::head_,
      compare_to_int<
         typename first::tail_,
         typename second::tail_
      >::result_
   >::result_;
};

template<typename first>
struct compare_to_int<first, empty_list_t>
{
   static const int result_ = 0;
};

template<typename second>
struct compare_to_int<empty_list_t, second>
{
   static const int result_ = 0;
};

template<>
struct compare_to_int<empty_list_t, empty_list_t>
{
   static const int result_ = 0;
};

template<int value>
struct abs_compare_int_tool
{
   static const int result_ = compare_int_tool<
      (value > 0),
      value,
      -value
   >::result_;
};

template<typename first, typename second>
struct compare_to
{
   static const int result_ = compare_int_tool<
      (length<first>::result_ != length<second>::result_),
      compare_int_tool<
         (length<first>::result_ - length<second>::result_ > 0),
         compare_to_int<
            first,
            typename shift<
               second,
               abs_compare_int_tool<
                  length<first>::result_ - length<second>::result_
               >::result_
            >::result_
         >::result_,
         compare_to_int<
            typename shift<
               first,
               abs_compare_int_tool<
                  length<second>::result_ - length<first>::result_
               >::result_
            >::result_,
            second
         >::result_
      >::result_,
      compare_to_int<
         first,
         second
      >::result_
   >::result_;
};